﻿using Lib.MonitLogs.Entitys;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using JavaScript = System.Text.Json.JsonSerializer;

namespace Lib.MonitLogs;

/// <summary>
/// 日志管理类
/// </summary>
public static class Logs {
    /// <summary>
    /// 静态构造函数
    /// </summary>
    static Logs() {
        _ = Logs.Initialize();
    }
    /// <summary>
    /// 
    /// </summary>
    static async Task Initialize() {
        //
        Console.WriteLine($"\n日志模块启动时间：{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
        //
        Opts = new JsonSerializerOptions() {
            // 处理中文转义问题（转义不安全字符） 
            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
            // 不使用驼峰样式
            PropertyNamingPolicy = null,
            // 忽略循环引用
            ReferenceHandler = ReferenceHandler.IgnoreCycles,
            // 处理注释
            ReadCommentHandling = JsonCommentHandling.Skip,
            // 忽略大小写
            PropertyNameCaseInsensitive = true,
            // 是否缩进
            WriteIndented = false
        };
        Opts.Converters.Add(new DateTimeConverter());
        Opts.Converters.Add(new DateTimeNullableConverter());
        Opts.Converters.Add(new TypeConverter());
        Opts.Converters.Add(new AssemblyConverter());
        Opts.Converters.Add(new JsonStringEnumConverter());
        //
        LogsKeys = [];
        LogPath = $"{AppDomain.CurrentDomain.BaseDirectory.Replace(@"\","/")}Logs/";
        if (Directory.Exists(LogPath)) {
           
        } else {
            Directory.CreateDirectory(LogPath);
        }
        Timer = new Timer((object State) => {
            var Day = DateTime.Now.Day;
            if (LogsKeys.Count > 0) {
                foreach (var Re in LogsKeys.ToList()) {
                    if (Re.Value.Day != Day) {
                        LogsKeys.Remove(Re.Key);
                    }
                }
                Console.WriteLine($"\n日志管理定时器执行时间：{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
            }
        }, null, 0, 3600000);
        LogsChannel = Channel.CreateUnbounded<LogEntry>();
        while (await LogsChannel.Reader.WaitToReadAsync()) {
            while (LogsChannel.Reader.TryRead(out var e)) {
                using var Stream = new StreamWriter(e.Path, true);
                await Stream.WriteLineAsync(e.Content);
            }
        }
    }

    /// <summary>
    /// 序列化选项
    /// </summary>
    static JsonSerializerOptions Opts { get; set; }
    /// <summary>
    /// 定时器
    /// </summary>
    internal static Timer Timer { get; set; }
    /// <summary>
    /// 
    /// </summary>
    internal static Channel<LogEntry> LogsChannel { get; set; }
    /// <summary>
    /// 
    /// </summary>
    internal static string LogPath { get; set; }
    /// <summary>
    /// 
    /// </summary>
    internal static Dictionary<string, LogEntry> LogsKeys { get; set; }



    /// <summary>
    /// 写入日志
    /// </summary>
    public static bool Write(string Content, string Key) {
        return LogsChannel.Writer.TryWrite(LogEntry.Create(Key, Content));
    }
    /// <summary>
    /// 写入日志
    /// </summary>
    public static async ValueTask WriteAsync(string Content, string Key) {
        await LogsChannel.Writer.WriteAsync(LogEntry.Create(Key, Content));
    }
    /// <summary>
    /// 写入日志
    /// </summary>
    public static bool Write(string Content, LogType LogType) {
        return Logs.Write(Content, LogType.ToString());
    }
    /// <summary>
    /// 写入日志
    /// </summary>
    public static async ValueTask WriteAsync(string Content, LogType LogType) {
        await Logs.WriteAsync(Content, LogType.ToString());
    }


    /// <summary>
    /// 写入日志
    /// </summary>
    public static bool Write<T>(T Entity, string Key) {
        return Logs.Write(JavaScript.Serialize(Entity, Opts), Key);
    }
    /// <summary>
    /// 
    /// </summary>
    public static async ValueTask WriteAsync<T>(T Entity, string Key) {
        await Logs.WriteAsync(JavaScript.Serialize(Entity, Opts), Key);
    }
    /// <summary>
    /// 写入日志
    /// </summary>
    public static bool Write<T>(T Entity, LogType LogType) {
        return Logs.Write(JavaScript.Serialize(Entity, Opts), LogType.ToString());
    }
    /// <summary>
    /// 
    /// </summary>
    public static async ValueTask WriteAsync<T>(T Entity, LogType LogType) {
        await Logs.WriteAsync(JavaScript.Serialize(Entity, Opts), LogType.ToString());
    }




    /// <summary>
    /// 异常日志
    /// </summary>
    public static bool Write(this Exception Ex, string Description = null) {
        return Logs.Write(JavaScript.Serialize(LogException.Create(Ex, Description), Opts), LogType.Exception.ToString());
    }
    /// <summary>
    /// 异常日志
    /// </summary>
    public static async ValueTask WriteAsync(this Exception Ex, string Description = null) {
        await Logs.WriteAsync(JavaScript.Serialize(LogException.Create(Ex, Description), Opts), LogType.Exception.ToString());
    }




    /// <summary>
    /// 写入日志
    /// </summary>
    public static bool Write(this LogEntity Entity, string Key) {
        return Logs.Write(JavaScript.Serialize(Entity, Opts), Key);
    }
    /// <summary>
    /// 写入日志
    /// </summary>
    public static async ValueTask WriteAsync(this LogEntity Entity, string Key) {
        await Logs.WriteAsync(JavaScript.Serialize(Entity, Opts), Key);
    }
    /// <summary>
    /// 写入日志
    /// </summary>
    public static bool Write(this LogEntity Entity, LogType LogType) {
        return Logs.Write(JavaScript.Serialize(Entity, Opts), LogType.ToString());
    }
    /// <summary>
    /// 写入日志
    /// </summary>
    public static async ValueTask WriteAsync(this LogEntity Entity, LogType LogType) {
        await Logs.WriteAsync(JavaScript.Serialize(Entity, Opts), LogType.ToString());
    }



}


